﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.Statistics
{
    /// <summary>
    /// This class provides the computation of the second order partial Pearson correlation coefficient.
    /// </summary>
    [Serializable]
    public class PartialSecondOrderPearsonCorrelation
    {
        /// <summary>
        /// The first vector for the correlation check.
        /// </summary>
        private GeneralVector vector1;

        /// <summary>
        /// The second vector for the correlation check.
        /// </summary>
        private GeneralVector vector2;

        /// <summary>
        /// The third vector for the correlation check.
        /// </summary>
        private GeneralVector vector3;

        /// <summary>
        /// The fourth vector for the correlation check.
        /// </summary>
        private GeneralVector vector4;

        /// <summary>
        /// Initializes a new instance of the <see cref="PartialSecondOrderPearsonCorrelation"/> class.
        /// </summary>
        /// <param name="vector1">The first vector for the correlation check.</param>
        /// <param name="vector2">The second vector for the correlation check.</param>
        /// <param name="vector3">The third vector for the correlation check.</param>
        /// <param name="vector4">The fourth vector for the correlation check.</param>
        public PartialSecondOrderPearsonCorrelation(GeneralVector vector1, GeneralVector vector2, GeneralVector vector3,
                                                    GeneralVector vector4)
        {
            if (vector1 == (GeneralVector) null)
            {
                throw new ArgumentNullException("vector1");
            }

            if (vector2 == (GeneralVector) null)
            {
                throw new ArgumentNullException("vector2");
            }

            if (vector3 == (GeneralVector) null)
            {
                throw new ArgumentNullException("vector3");
            }

            if (vector4 == (GeneralVector) null)
            {
                throw new ArgumentNullException("vector4");
            }

            this.vector1 = vector1;
            this.vector2 = vector2;
            this.vector3 = vector3;
            this.vector4 = vector4;
        }

        /// <summary>
        /// The first vector for the correlation check.
        /// </summary>
        public GeneralVector Vector1
        {
            get { return this.vector1; }
            set { this.vector1 = value; }
        }

        /// <summary>
        /// The second vector for the correlation check.
        /// </summary>
        public GeneralVector Vector2
        {
            get { return this.vector2; }
            set { this.vector2 = value; }
        }

        /// <summary>
        /// The third vector for the correlation check.
        /// </summary>
        public GeneralVector Vector3
        {
            get { return this.vector3; }
            set { this.vector3 = value; }
        }

        /// <summary>
        /// The fourth vector for the correlation check.
        /// </summary>
        public GeneralVector Vector4
        {
            get { return this.vector4; }
            set { this.vector4 = value; }
        }

        /// <summary>
        /// Computes the second order partial correlation coefficient.
        /// </summary>
        /// <returns>The second order partial correlation coefficient.</returns>
        public double ComputeCorrelationCoefficient()
        {
            if ((this.vector1.Count != this.vector2.Count) || (this.vector1.Count != this.vector3.Count) ||
                (this.vector1.Count != this.vector4.Count))
            {
                throw new ArgumentException("The number of components of vector 1, 2, 3 and 4 have to be even.");
            }

            if ((this.vector2.Count != this.vector3.Count) || (this.vector2.Count != this.vector4.Count))
            {
                throw new ArgumentException("The number of components of vector 1, 2, 3 and 4 have to be even.");
            }

            if (this.vector3.Count != this.vector4.Count)
            {
                throw new ArgumentException("The number of components of vector 1, 2, 3 and 4 have to be even.");
            }

            PartialPearsonCorrelation r123Engine = new PartialPearsonCorrelation(this.vector1, this.vector2,
                                                                                 this.vector3);
            PartialPearsonCorrelation r143Engine = new PartialPearsonCorrelation(this.vector1, this.vector4,
                                                                                 this.vector3);
            PartialPearsonCorrelation r243Engine = new PartialPearsonCorrelation(this.vector2, this.vector4,
                                                                                 this.vector3);

            double r123 = r123Engine.ComputeCorrelationCoefficient();
            double r143 = r143Engine.ComputeCorrelationCoefficient();
            double r243 = r243Engine.ComputeCorrelationCoefficient();

            return (r123 - r143*r243)/(Math.Sqrt(1 - Math.Pow(r143, 2)*Math.Sqrt(1 - Math.Pow(r243, 2))));
        }
    }
}